package com.ls.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ls.config.redis.RedisClient;
import com.ls.config.satoken.SaTokenUtilPy;
import com.ls.controller.booking.model.*;
import com.ls.entity.*;
import com.ls.enums.MwFailCodeEnum;
import com.ls.enums.SignEnum;
import com.ls.mapper.BookingMapper;
import com.ls.service.*;
import com.ls.utils.ResultData;
import com.ls.utils.sms.ReduceSmsUtil;
import com.ls.utils.sms.SendSmsModel;
import com.ls.utils.sms.SmsPyUtil;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ls.constant.SystemConstants.*;


/**
 * <p>
 * 预定服务实现类
 * </p>
 *
 * @author pengyu
 * @since 2024-06-28
 */
@Service
@Slf4j
public class BookingServiceImpl extends ServiceImpl<BookingMapper, Booking> implements IBookingService {
    private final ILinkmanService linkmanService;
    private final ICompanyService companyService;
    @Lazy
    private final ISeatingService seatingService;
    @Lazy
    private final IBoothService boothService;
    @Lazy
    private final IBookNoteService bookNoteService;
    private final IPhoneRecordService phoneRecordService;
    private final IBookingTimeService bookingTimeService;
    private final ICustomerService customerService;
    @Lazy
    private final IInviteService inviteService;
    private final IYxSmsService yxSmsService;
    private final IYxFieldService yxFieldService;
    private final RedisClient redisClient;
    private final ReduceSmsUtil reduceSmsUtil;

    @Autowired
    public BookingServiceImpl(
            ILinkmanService linkmanService,
            ICompanyService companyService,
            @Lazy ISeatingService seatingService,
            @Lazy IBoothService boothService,
            @Lazy IBookNoteService bookNoteService,
            IPhoneRecordService phoneRecordService,
            IBookingTimeService bookingTimeService,
            ICustomerService customerService,
            @Lazy IInviteService inviteService,
            IYxSmsService yxSmsService,
            IYxFieldService yxFieldService,
            RedisClient redisClient,
            ReduceSmsUtil reduceSmsUtil
    ) {
        this.linkmanService = linkmanService;
        this.companyService = companyService;
        this.seatingService = seatingService;
        this.boothService = boothService;
        this.bookNoteService = bookNoteService;
        this.phoneRecordService = phoneRecordService;
        this.bookingTimeService = bookingTimeService;
        this.customerService = customerService;
        this.inviteService = inviteService;
        this.yxSmsService = yxSmsService;
        this.yxFieldService = yxFieldService;
        this.redisClient = redisClient;
        this.reduceSmsUtil = reduceSmsUtil;
    }

    /**
     * 最近一次预定/沟通记录
     */
    @Override
    public ResultData pageList(QueryBookingModel model) {
        log.info("查询预定列表：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        // 构建联系人子查询
        List<Long> linkmanIds = linkmanService.list(new LambdaQueryWrapper<Linkman>()
                        .eq(Linkman::getCustomerId, customerId)
                        .like(StringUtils.isNotBlank(model.getSearch()), Linkman::getLinkmanName, model.getSearch())
                        .or()
                        .like(StringUtils.isNotBlank(model.getSearch()), Linkman::getFullSpellName, model.getSearch())
                        .or()
                        .like(StringUtils.isNotBlank(model.getSearch()), Linkman::getShortSpellName, model.getSearch())
                        .or()
                        .like(StringUtils.isNotBlank(model.getSearch()), Linkman::getLinkmanPhone, model.getSearch())
                ).stream()
                .map(Linkman::getLinkmanId)
                .collect(Collectors.toList());
        log.info("查询联系人列表：{}", linkmanIds);
        // 获取每个联系人的最新预定ID
        List<Long> latestBookingIds = getBaseMapper().selectLatestBookingIds(customerId);
        log.info("查询最新预定列表：{}", latestBookingIds.isEmpty());
        // 构建主查询（只查询最新预定记录）
        LambdaQueryWrapper<Booking> wrapper = new LambdaQueryWrapper<Booking>()
//                .in(!latestBookingIds.isEmpty(), Booking::getBookingId, latestBookingIds)
//                .in(StringUtils.isNotBlank(model.getSearch()), Booking::getLinkmanId, linkmanIds)
                .eq(Booking::getCustomerId, customerId)
                .eq(StringUtils.isNotBlank(model.getSearch())&&CollectionUtils.isEmpty(linkmanIds),Booking::getBookingStatus, -1)
                .orderByDesc(Booking::getCreateTime);
        if (CollectionUtils.isNotEmpty(linkmanIds)) {
            wrapper.in(Booking::getLinkmanId, linkmanIds);
        }
        if (CollectionUtils.isNotEmpty(latestBookingIds)) {
            wrapper.in(Booking::getBookingId,latestBookingIds);
        }
        Page<Booking> page = new Page<>(model.getPageNum(), model.getPageSize());
        IPage<Booking> bookingPage = this.page(page, wrapper);
        IPage<ListBookingVo> resultPage = bookingPage.convert(booking -> {
            log.info("查询预定列表：{}", booking);
            ListBookingVo vo = new ListBookingVo();
            BeanUtils.copyProperties(booking, vo);
            // 填充基础字段
            vo.setLinkmanId(booking.getLinkmanId());

            // 获取关联数据
            Linkman linkman = linkmanService.getById(booking.getLinkmanId());
            Seating seating = seatingService.getById(booking.getSeatingId());
            Booth booth = boothService.getById(booking.getBoothId());
            // 设置关联字段
            vo.setLinkmanName(linkman.getLinkmanName());
            vo.setLinkmanPhone(linkman.getLinkmanPhone());
            if (booking.getBookingType() == NUMBER_1) {
                vo.setContent(getContent(booking));
            } else {
                BookNote bookNote = bookNoteService.getOne(new LambdaQueryWrapper<BookNote>()
                        .eq(BookNote::getBookingId, booking.getBookingId())
                );
                vo.setContent(bookNote.getContent());
            }
            vo.setCreateTime(booking.getCreateTime());
            vo.setBookingId(booking.getBookingId());
            vo.setBookingStatus(booking.getBookingStatus());
            Customer customer1 = customerService.getById(booking.getCustomerId());
            String nickname;
            if (StringUtils.isNotEmpty(customer1.getNickname())){
                nickname = customer1.getNickname();
            }else {
                nickname = "匿名";
            }
            vo.setStaffName(nickname);
            vo.setIsSaved(NUMBER_1);
            return vo;
        });

        return ResultData.successData(resultPage);
    }

    /**
     * 获取预定内容
     */
    public String getContent(Booking booking) {
        if (booking.getBookingDay()==null){
            return "";
        }
        String content = booking.getBookingDay() + " " + booking.getArrivalTime() + " " + seatingService.getById(booking.getSeatingId()).getSeatingName() + " " + boothService.getById(booking.getBoothId()).getBoothName() + " " + booking.getArrivalNum() + "人";
        return content;
    }

    /**
     * 添加预定
     */
    @Override
    public ResultData add(AddBookingModel model) {
        log.info("新增联系人参数添加预定：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        Long companyId = null;
        if (!model.getLinkmanPhone().matches(PHONE_NUMBER_VALID_REGEX)) {
            return ResultData.failure("手机号码格式错误");
        }
        if (model.getCompanyId() == null) {
            Company company = companyService.getOne(new LambdaQueryWrapper<Company>().eq(Company::getCustomerId, customerId));
            companyId = company.getCompanyId();
        } else {
            companyId = model.getCompanyId();
        }
        if (companyId == null){
            return ResultData.failure("请先设置企业");
        }
        List<Booking> bookings = list(new LambdaQueryWrapper<Booking>()
                .eq(Booking::getCustomerId, customerId)
                .eq(Booking::getBookingDay, model.getBookingDay())
                .eq(Booking::getSeatingId, model.getSeatingId())
                .eq(Booking::getBoothId, model.getBoothId())
                .eq(Booking::getTimeId, model.getTimeId())
                .ne(Booking::getBookingStatus, 5)
        );
        if (bookings.size()!=0) {
            return ResultData.failure("该时间段已存在预定！");
        }
        LocalTime arrivalTime = model.getArrivalTime();
        LocalTime startTime = bookingTimeService.getById(model.getTimeId()).getStartTime().minusHours(1);
        LocalTime endTime = bookingTimeService.getById(model.getTimeId()).getEndTime().plusHours(2);
        if (arrivalTime.isBefore(startTime) || arrivalTime.isAfter(endTime)) {
            return ResultData.failure("请选择正确的时间段！" + startTime + "至" + endTime);
        }
        Booking booking = new Booking();
        BeanUtils.copyProperties(model, booking);
        if (model.getLinkmanId() == null) {
            Linkman linkman = linkmanService.getOne(new LambdaQueryWrapper<Linkman>()
                    .eq(Linkman::getCustomerId, customerId)
                    .eq(Linkman::getValidFlag, VALID_TRUE)
                    .eq(Linkman::getLinkmanType, model.getLinkmanType())
                    .eq(Linkman::getCompanyId, companyId)
                    .eq(Linkman::getLinkmanPhone, model.getLinkmanPhone())
                    .last("limit 1")
            );
            if (linkman == null) {
                linkman = new Linkman();
                BeanUtils.copyProperties(model, linkman);
                Name(model.getLinkmanName(), linkman);
                linkman.setCompanyId(companyId);
                linkman.setCustomerId(customerId);
                linkman.setCreatorId(customerId);
                linkman.setUpdaterId(customerId);
                linkman.setUpdateTime(LocalDateTime.now());
                linkman.setCreateTime(LocalDateTime.now());
                linkman.setValidFlag(VALID_TRUE);
                linkman.insert();
            }
            booking.setLinkmanId(linkman.getLinkmanId());
        } else {
            booking.setLinkmanId(model.getLinkmanId());
        }
        booking.setCompanyId(companyId);
        booking.setCustomerId(customerId);
        booking.setBookingStatus(NUMBER_1);
        BookingTime bookingTime = bookingTimeService.getById(model.getTimeId());
        booking.setStartTime(bookingTime.getStartTime());
        booking.setEndTime(bookingTime.getEndTime());
        saveOrUpdate(booking);
        BookNote bookNote = new BookNote();
        bookNote.setBookingId(booking.getBookingId());
        bookNote.setContent(model.getRemark());
        bookNote.setCompanyId(companyId);
        bookNote.setCustomerId(customerId);
        bookNote.setLinkmanId(booking.getLinkmanId());
        bookNote.setBookingSource(model.getBookingSource());
        bookNote.setBookingStatus(booking.getBookingStatus());
        bookNote.setBookingContent(getContent(booking));
        bookNote.insert();
        log.info("新增预定booking.getBookingStatus：{}", booking.getBookingStatus());
        return getSendStatus(booking.getBookingId());
    }
    /**
     * 修改预定内容
     */
    @Override
    public ResultData edit(EditBookingModel model) {
        log.info("修改预定内容：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        Long companyId = null;
        if (model.getCompanyId() == null) {
            Company company = companyService.getOne(new LambdaQueryWrapper<Company>().eq(Company::getCustomerId, customerId));
            companyId = company.getCompanyId();
        } else {
            companyId = model.getCompanyId();
        }
        if (companyId == null){
            return ResultData.failure("请先设置企业");
        }
        List<Booking> bookings = list(new LambdaQueryWrapper<Booking>()
                .eq(Booking::getCustomerId, customerId)
                .eq(Booking::getBookingDay, model.getBookingDay())
                .eq(Booking::getSeatingId, model.getSeatingId())
                .eq(Booking::getBoothId, model.getBoothId())
                .eq(Booking::getTimeId, model.getTimeId())
                .ne(Booking::getBookingStatus, 5)
                .ne(Booking::getBookingId, model.getBookingId())
        );
        if (bookings.size()!=0) {
            return ResultData.failure("该时间段已存在预定！");
        }
        LocalTime arrivalTime = model.getArrivalTime();
        LocalTime startTime = bookingTimeService.getById(model.getTimeId()).getStartTime().minusHours(1);
        LocalTime endTime = bookingTimeService.getById(model.getTimeId()).getEndTime().plusHours(2);
        if (arrivalTime.isBefore(startTime) || arrivalTime.isAfter(endTime)) {
            return ResultData.failure("请选择正确的时间段！" + startTime + "至" + endTime);
        }
        Booking booking = getById(model.getBookingId());
        BeanUtils.copyProperties(model, booking);
        booking.setBookingStatus(NUMBER_2);
        BookingTime bookingTime = bookingTimeService.getById(model.getTimeId());
        booking.setStartTime(bookingTime.getStartTime());
        booking.setEndTime(bookingTime.getEndTime());
        updateById(booking);
        BookNote bookNote = new BookNote();
        bookNote.setBookingId(model.getBookingId());
        bookNote.setContent(model.getRemark());
        bookNote.setCompanyId(companyId);
        bookNote.setCustomerId(customerId);
        bookNote.setBookingSource(model.getBookingSource());
        bookNote.setBookingStatus(booking.getBookingStatus());
        bookNote.setBookingContent(model.getRemark());
        bookNote.setLinkmanId(booking.getLinkmanId());
        bookNote.insert();
        BookSendSmsModel bookSendSmsModel = new BookSendSmsModel();
        bookSendSmsModel.setBookingId(booking.getBookingId());
        log.info("修改预定内容booking.getBookingStatus：{}", booking.getBookingStatus());
        return getSendStatus(booking.getBookingId());
    }
    /**获取发送状态*/
    public ResultData getSendStatus(Long bookingId) {
        Booking booking = getById(bookingId);
        Invite invite = inviteService.getOne(new LambdaQueryWrapper<Invite>().eq(Invite::getCustomerId, booking.getCustomerId()));
        BookSendSmsModel bookSendSmsModel = new BookSendSmsModel();
        //返回0代表邀请函内容未填写，需要联系客服，1代表生成成功,2代表短信余额不足
        if (invite==null||invite.getBannerImg().isEmpty() || invite.getMessage().isEmpty() || invite.getAddress().isEmpty()) {
            bookSendSmsModel.setType(NUMBER_0);
        }
//        YxSms yxSms = yxSmsService.getById(invite.getYxSmsId());
        Customer customer = customerService.getById(booking.getCustomerId());
        if (customer.getSmsTotal()==0){
            bookSendSmsModel.setType(NUMBER_2);
        }
        if (bookSendSmsModel.getType()==null){
            bookSendSmsModel.setType(NUMBER_1);
        }
        bookSendSmsModel.setBookingId(bookingId);
        bookSendSmsModel.setInviteId(invite.getInviteTemplateId());
        Linkman linkman = linkmanService.getById(booking.getLinkmanId());
        BeanUtils.copyProperties(linkman, bookSendSmsModel);
        BeanUtils.copyProperties(booking, bookSendSmsModel);
        log.info("发送状态返回booking.getBookingStatus：{}", booking.getBookingStatus());
        return ResultData.successData(bookSendSmsModel);
    }
    /**
     * 新增跟进记录
     */
    @Override
    public ResultData addBookNote(AddBooknoteModel model) {
        log.info("新增联系人参数添加跟进记录：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        Long companyId = null;
        if (!model.getLinkmanPhone().matches(PHONE_NUMBER_VALID_REGEX)) {
            return ResultData.failure("手机号码格式错误");
        }
        if (model.getCompanyId() == null) {
            Company company = companyService.getOne(new LambdaQueryWrapper<Company>().eq(Company::getCustomerId, customerId));
            companyId = company.getCompanyId();
        } else {
            companyId = model.getCompanyId();
        }
        Booking booking = new Booking();
        BeanUtils.copyProperties(model, booking);
        if (model.getLinkmanId() == null) {
            Linkman linkman = linkmanService.getOne(new LambdaQueryWrapper<Linkman>()
                    .eq(Linkman::getCustomerId, customerId)
                    .eq(Linkman::getValidFlag, VALID_TRUE)
                    .eq(Linkman::getLinkmanType, model.getLinkmanType())
                    .eq(Linkman::getCompanyId, companyId)
                    .eq(Linkman::getLinkmanPhone, model.getLinkmanPhone())
                    .last("limit 1")
            );
            if (linkman == null) {
                linkman = new Linkman();
                BeanUtils.copyProperties(model, linkman);
                Name(model.getLinkmanName(), linkman);
                linkman.setCompanyId(companyId);
                linkman.setCustomerId(customerId);
                linkman.setCreatorId(customerId);
                linkman.setUpdaterId(customerId);
                linkman.setUpdateTime(LocalDateTime.now());
                linkman.setCreateTime(LocalDateTime.now());
                linkman.setValidFlag(VALID_TRUE);
                linkman.insert();
            }
            booking.setLinkmanId(linkman.getLinkmanId());
        } else {
            booking.setLinkmanId(model.getLinkmanId());
        }
        booking.setCompanyId(companyId);
        booking.setCustomerId(customerId);
        booking.setBookingStatus(NUMBER_0);
//        saveOrUpdate(booking);
        BookNote bookNote = new BookNote();
        bookNote.setContent(model.getRemark());
        bookNote.setCompanyId(companyId);
        bookNote.setCustomerId(customerId);
        bookNote.setLinkmanId(booking.getLinkmanId());
        bookNote.setBookingSource(model.getBookingSource());
        bookNote.setBookingStatus(6);
        Boolean flag = bookNote.insert();
        log.info("添加跟进记录booking.getBookingStatus：{}", booking.getBookingStatus());
        if (flag) {
            return ResultData.successMsg("添加成功");
        } else {
            return ResultData.failure("添加失败");
        }
    }



    /**
     * 修改预定状态
     */
    @Override
    public ResultData updateStatus(BookingStatusModel model) {
        log.info("修改预定状态：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        Long companyId = null;
        if (model.getCompanyId() == null) {
            Company company = companyService.getOne(new LambdaQueryWrapper<Company>().eq(Company::getCustomerId, customerId));
            log.info("用户企业：{}", company);
            companyId = company.getCompanyId();
        } else {
            companyId = model.getCompanyId();
        }
        Booking booking = getById(model.getBookingId());
        booking.setBookingStatus(model.getBookingStatus());
        updateById(booking);
        BookNote bookNote = new BookNote();
        bookNote.setBookingId(model.getBookingId());
        bookNote.setCompanyId(companyId);
        bookNote.setCustomerId(customerId);
        bookNote.setBookingSource(model.getBookingSource());
        bookNote.setBookingStatus(booking.getBookingStatus());
        bookNote.setBookingContent(getContent(booking));
        bookNote.setLinkmanId(booking.getLinkmanId());
        bookNote.insert();
        log.info("修改预定状态booking.getBookingStatus：{}", booking.getBookingStatus());
        return ResultData.successMsg("修改成功");
    }

    /**
     * 设置联系人全拼和简拼
     */
    private void Name(String name, Linkman linkman) {
        if (StringUtils.isNotEmpty(name)) {
            // 获取联系人名字的全拼和简拼
            StringBuilder fullSpell = new StringBuilder();
            StringBuilder shortSpell = new StringBuilder();

            for (char c : name.toCharArray()) {
                String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
                if (pinyinArray != null && pinyinArray.length > 0) {
                    // 取第一个发音（多音字场景）
                    String pinyin = pinyinArray[0].replaceAll("\\d", "");
                    fullSpell.append(pinyin);
                    shortSpell.append(pinyin.charAt(0));
                } else {
                    // 非汉字字符直接保留
                    fullSpell.append(c);
                    shortSpell.append(c);
                }
            }
            // 直接设置到linkman对象
            linkman.setFullSpellName(fullSpell.toString().toLowerCase());
            linkman.setShortSpellName(shortSpell.toString().toLowerCase());
        }
    }

    /**
     * 客户跟进记录 查看联系人预定次数统计
     */
    @Override
    public ResultData getBooking(GetBookingModel model) {
        log.info("查询预定记录：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        Linkman linkman = linkmanService.getById(model.getLinkmanId());
        BookingInfoVo bookingInfoVo = new BookingInfoVo();
        BeanUtils.copyProperties(linkman, bookingInfoVo);

        List<Booking> bookings = list(new LambdaQueryWrapper<Booking>()
                .eq(Booking::getLinkmanId, model.getLinkmanId())
                .eq(Booking::getCustomerId, customerId)
                .eq(Booking::getBookingType, 1)
                .orderByDesc(Booking::getCreateTime)
        );
        if (bookings.size() > 0) {
            List<Booking> bookings1 = list(new LambdaQueryWrapper<Booking>()
                    .eq(Booking::getLinkmanId, model.getLinkmanId())
                    .eq(Booking::getCustomerId, customerId)
                    .eq(Booking::getBookingStatus, 5)
                    .eq(Booking::getBookingType, 1)
                    .orderByDesc(Booking::getCreateTime)
            );
            bookingInfoVo.setBookingNum(bookings.size());
            bookingInfoVo.setCancelNum(bookings1.size());
            Booking booking = bookings.get(0);
            bookingInfoVo.setContent(getContent(booking));
            bookingInfoVo.setBookingId(booking.getBookingId());
        }
        return ResultData.successData(bookingInfoVo);
    }

    /**
     * 近期联系记录 最近通话用户
     */
    @Override
    public ResultData getRecentPhoneRecord() {
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        //获取这个星期一的00：00：00和这个星期天的23：59：59
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now().with(DayOfWeek.MONDAY), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now().with(DayOfWeek.SUNDAY), LocalTime.MAX);
        List<PhoneRecord> phoneRecords = phoneRecordService.list(new LambdaQueryWrapper<PhoneRecord>()
                .eq(PhoneRecord::getCustomerId, customerId)
                .between(PhoneRecord::getStartTime, startTime, endTime)
                .orderByDesc(PhoneRecord::getStartTime)
        );
        // 新增去重逻辑（使用Java Stream API）
        List<PhoneRecord> distinctRecords = phoneRecords.stream()
                .collect(Collectors.toMap(
                        PhoneRecord::getOuterPhone,
                        Function.identity(),
                        (existing, replacement) -> existing
                ))
                .values()
                .stream()
                .collect(Collectors.toList());
        List<ListBookingVo> resultList = distinctRecords.stream().map(record -> {
            ListBookingVo vo = new ListBookingVo();
            BeanUtils.copyProperties(record, vo);
            // 通过电话号码查询联系人
            Linkman linkman = linkmanService.getOne(new LambdaQueryWrapper<Linkman>()
                    .eq(Linkman::getCustomerId, customerId)
                    .eq(Linkman::getValidFlag, VALID_TRUE)
                    .eq(Linkman::getLinkmanPhone, record.getOuterPhone())
                    .last("limit 1")
            );

            // 设置基础信息
            if (linkman != null) {
                //查询联系人最新一条预定信息
                Booking booking = getOne(new LambdaQueryWrapper<Booking>()
                        .eq(Booking::getLinkmanId, linkman.getLinkmanId())
                        .eq(Booking::getCustomerId, customerId)
                        .orderByDesc(Booking::getCreateTime)
                );
                vo.setLinkmanId(linkman.getLinkmanId());
                vo.setLinkmanName(linkman.getLinkmanName());
                vo.setLinkmanPhone(linkman.getLinkmanPhone());
                vo.setContent(getContent(booking));
            } else {
                vo.setLinkmanPhone(record.getOuterPhone());
                vo.setCreateTime(record.getStartTime());
            }
            return vo;
        }).collect(Collectors.toList());
        return ResultData.successData(resultList);

    }

    /**
     * 近期联系记录 获取所有联系人及预定记录
     */
    @Override
    public ResultData getAllLinkman(List<PhoneRecordModel> phoneList) {
        log.info("近期联系记录 获取所有联系人及预定记录：{}", phoneList);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        //对phoneList实现根据对象中的phone去重
        // 新增去重逻辑：按phone分组，保留createTime最新的一条
        Map<String, PhoneRecordModel> distinctPhones = phoneList.stream()
                .collect(Collectors.toMap(
                        PhoneRecordModel::getPhone,
                        Function.identity(),
                        (existing, replacement) ->
                                existing.getCreateTime().isAfter(replacement.getCreateTime()) ? existing : replacement
                ));
        List<ListBookingVo> resultList = distinctPhones.values().stream().map(phoneRecord -> {
            log.info("查询联系人：{}", phoneRecord);
            ListBookingVo vo = new ListBookingVo();
            // 通过电话号码查询联系人
            Linkman linkman = linkmanService.getOne(new LambdaQueryWrapper<Linkman>()
                    .eq(Linkman::getCustomerId, customerId)
                    .eq(Linkman::getValidFlag, VALID_TRUE)
                    .eq(Linkman::getLinkmanPhone, phoneRecord.getPhone())
                    .last("limit 1")
            );

            // 设置基础信息
            if (linkman != null) {
                //查询联系人最新一条预定信息
                Booking booking = getOne(new LambdaQueryWrapper<Booking>()
                        .eq(Booking::getLinkmanId, linkman.getLinkmanId())
                        .eq(Booking::getCustomerId, customerId)
                        .orderByDesc(Booking::getCreateTime)
                        .last("LIMIT 1")
                );
                if (booking != null) {
                    vo.setContent(getContent(booking));
                    vo.setBookingId(booking.getBookingId());
                    vo.setCreateTime(booking.getCreateTime());
                    Customer customer1 = customerService.getById(booking.getCustomerId());
                    vo.setStaffName(customer1.getNickname());
                    vo.setBookingStatus(booking.getBookingStatus());
                } else {
                    vo.setCreateTime(phoneRecord.getCreateTime());
                }
                vo.setLinkmanPhone(linkman.getLinkmanPhone());
                vo.setLinkmanName(linkman.getLinkmanName());
                vo.setLinkmanId(linkman.getLinkmanId());
                vo.setIsSaved(NUMBER_1);
            } else {
                vo.setLinkmanPhone(phoneRecord.getPhone());
                vo.setCreateTime(phoneRecord.getCreateTime());
                vo.setLinkmanName(phoneRecord.getName());
                vo.setIsSaved(NUMBER_0);
            }
            return vo;
        }).collect(Collectors.toList());
        return ResultData.successData(resultList);
    }

    /**
     * 获取当天预定的情况
     */
    @Override
    public ResultData getTodayBooking(BookingModel model) {
        log.info("获取当天预定情况：{}", model);
        Customer customer = SaTokenUtilPy.getCustomer();
        Long customerId = customer.getCustomerId();
        Long companyId = null;
        if (model.getCompanyId() == null) {
            Company company = companyService.getOne(new LambdaQueryWrapper<Company>().eq(Company::getCustomerId, customerId));
            log.info("用户企业：{}", company);
            if (company == null) {
                return ResultData.failure("请先设置企业");
            }
            companyId = company.getCompanyId();
        } else {
            companyId = model.getCompanyId();
        }
        if (companyId == null) {
            return ResultData.failure("请先设置企业");
        }
        if (model.getBookingDay() == null) {
            return ResultData.failure("预定日期不能为空");
        }


        // 修复2：添加空值检查
        List<Seating> seatings = seatingService.list(new LambdaQueryWrapper<Seating>()
                .eq(Seating::getCompanyId, companyId)
                .eq(Seating::getValidFlag, VALID_TRUE)
                .orderByAsc(Seating::getSeatingIndex)
                .orderByDesc(Seating::getCreateTime)
        );

        if (seatings.isEmpty()) {
            return ResultData.successData(Collections.emptyList());
        }

        List<TodayBookingVo> resultList = seatings.stream().map(seating -> {
            TodayBookingVo seatingVo = new TodayBookingVo();
            seatingVo.setSeatingId(seating.getSeatingId());
            seatingVo.setSeatingName(seating.getSeatingName());
            seatingVo.setSeatingIndex(seating.getSeatingIndex());

            // 修复3：添加卡座查询空值处理
            List<Booth> booths = boothService.list(new LambdaQueryWrapper<Booth>()
                    .eq(Booth::getSeatingId, seating.getSeatingId())
                    .eq(Booth::getValidFlag, VALID_TRUE)
                    .orderByAsc(Booth::getBoothIndex)
                    .orderByDesc(Booth::getCreateTime)
            );

            if (booths.size() > 0) {
                seatingVo.setBoothLists(booths.stream().map(booth -> {
                    TodayBookingVo.BoothSchedule boothSchedule = new TodayBookingVo.BoothSchedule();
                    boothSchedule.setBoothId(booth.getBoothId());
                    boothSchedule.setBoothName(booth.getBoothName());
                    boothSchedule.setBoothNum(booth.getBoothNum());
                    boothSchedule.setBoothRemark(booth.getBoothRemark());
                    boothSchedule.setBoothIndex(booth.getBoothIndex());
                    List<Integer> timeSlotsToCheck = (model.getTimeId() == null)
                            ? Arrays.asList(1, 2, 3, 4)
                            : Collections.singletonList(model.getTimeId());
                    List<TodayBookingVo.TimeSlot> timeSlots = timeSlotsToCheck.stream()
                            .map(time -> {
                                LambdaQueryWrapper<Booking> queryWrapper = new LambdaQueryWrapper<Booking>();
                                queryWrapper.eq(Booking::getSeatingId, seating.getSeatingId())
                                        .eq(Booking::getBoothId, booth.getBoothId())
                                        .eq(Booking::getTimeId, time)
                                        .eq(Booking::getBookingType, NUMBER_1)
                                        .eq(Booking::getBookingDay, model.getBookingDay())
                                        .eq(Booking::getCustomerId, customerId)
                                        .ne(Booking::getBookingStatus, 5).last("LIMIT 1");
                                Booking booking = getOne(queryWrapper);
                                TodayBookingVo.TimeSlot timeSlot = new TodayBookingVo.TimeSlot();
                                timeSlot.setTimeId(time);
                                //返回到店状态
                                if (booking!=null&&booking.getBookingStatus()!=3){
                                    LocalDateTime now = LocalDateTime.now();
                                    LocalDateTime arrivalDateTime = null;
                                    if (model.getBookingDay() != null && booking.getArrivalTime() != null) {
                                        arrivalDateTime = LocalDateTime.of(model.getBookingDay(), booking.getArrivalTime());
                                    }
                                    // 状态4：临近未到店（未来十分钟内）
                                    boolean isNear = arrivalDateTime != null
                                            && arrivalDateTime.isAfter(now)
                                            && arrivalDateTime.isBefore(now.plusMinutes(10));
                                    log.info("预约时间：{}", isNear);
                                    log.info("预约时间：{}", arrivalDateTime);
                                    // 状态5：超时未到店
                                    boolean isTimeout =  arrivalDateTime != null
                                            && arrivalDateTime.isBefore(now);
                                    Integer number = 1;
                                    if (isNear){
                                        number = 2;
                                    }
                                    if (isTimeout){
                                        number = 3;
                                    }
                                    if (booking.getBookingStatus()==3){
                                        number = 4;
                                    }
                                    timeSlot.setArriveStatus(number);
                                }
                                //返回到店状态 end
                                if (booking != null) {
                                    //全部状态的联系人或不包含可预定的
                                    Linkman linkman = linkmanService.getById(booking.getLinkmanId());
                                    timeSlot.setLinkmanId(linkman.getLinkmanId());
                                    timeSlot.setLinkmanName(linkman.getLinkmanName());
                                    //取手机号后四位
                                    if (linkman.getLinkmanPhone() != null) {
//                                        .substring(linkman.getLinkmanPhone().length() - 4)
                                        timeSlot.setLinkmanPhone(linkman.getLinkmanPhone());
                                    }
                                    timeSlot.setBookingId(booking.getBookingId());
                                    timeSlot.setAvailable(NUMBER_0);
                                    timeSlot.setBookingStatus(booking.getBookingStatus());
                                    timeSlot.setTimeId(booking.getTimeId());
                                    timeSlot.setArrivalTime(booking.getArrivalTime());
                                } else {
                                    //当前时段是否可预约
                                    if (model.getBookingDay().isBefore(LocalDate.now())) {
                                        log.info("用户预约时间小于今天：{}", model.getBookingDay());
                                        timeSlot.setAvailable(NUMBER_MINUS_1);
                                    } else if (model.getBookingDay().isAfter(LocalDate.now())) {
                                        log.info("用户预约时间大于今天：{}", model.getBookingDay());
                                        timeSlot.setAvailable(NUMBER_1);
                                    } else {
                                        BookingTime bookingTime = bookingTimeService.getById(time);
                                        if (LocalTime.now().isBefore(bookingTime.getEndTime().minusMinutes(9).minusSeconds(59))) {
                                            timeSlot.setAvailable(NUMBER_1);
                                        } else {
                                            timeSlot.setAvailable(NUMBER_MINUS_1);
                                        }
                                    }
                                }
                                return timeSlot;
                            }).collect(Collectors.toList());
                    if (model.getStatus() != null) {
                        timeSlots = Optional.ofNullable(timeSlots).orElse(Collections.emptyList())
                                .stream()
                                .filter(Objects::nonNull)
                                .filter(timeSlot -> {
                                    // 状态4：临近未到店（未来十分钟内）
                                    boolean isNear = model.getStatus() == 4
                                            &&timeSlot.getArriveStatus() != null
                                            && timeSlot.getArriveStatus()==2;

                                    // 状态5：超时未到店
                                    boolean isTimeout = model.getStatus() == 5
                                            &&timeSlot.getArriveStatus() != null
                                            && timeSlot.getArriveStatus()==3;
                                    log.info("预约状态：{}", timeSlot.getAvailable());
                                    return ((model.getStatus() == 1 && timeSlot.getAvailable() != null && timeSlot.getAvailable() == 0) ||
                                            (model.getStatus() == 2 && timeSlot.getAvailable() != null && timeSlot.getAvailable() == 1) ||
                                            (model.getStatus() == 3 && timeSlot.getBookingStatus() != null && timeSlot.getBookingStatus() == 3) ||
                                            isNear ||
                                            isTimeout);
                                })
                                .filter(Objects::nonNull)
                                .collect(Collectors.toList());
                    }
                    boothSchedule.setTimeSlots(timeSlots);
                    return boothSchedule;
                }).collect(Collectors.toList()));
            }

            return seatingVo;
        }).collect(Collectors.toList());

        return ResultData.successData(resultList);
    }

    /**
     * 根据id查询
     */
    @Override
    public ResultData getBookingById(Long bookingId) {
        Booking booking = getById(bookingId);
        return ResultData.successData(booking);
    }

    /**
     * 根据id获取预定及联系人信息
     */
    @Override
    public ResultData getBookingAndLinkman(Long bookingId) {
        if (bookingId == null) {
            return ResultData.success();
        }
        Booking booking = getById(bookingId);
        BookH5Vo bookH5Vo = new BookH5Vo();
        BeanUtils.copyProperties(booking, bookH5Vo);
        bookH5Vo.setSeatingName(seatingService.getById(booking.getSeatingId()).getSeatingName());
        bookH5Vo.setBoothName(boothService.getById(booking.getBoothId()).getBoothName());
        Linkman linkman = linkmanService.getById(booking.getLinkmanId());
        String name = linkman.getLinkmanName();
        bookH5Vo.setLinkmanPhone(linkman.getLinkmanPhone());
        boolean hasTitle = name != null && (name.contains("先生") || name.contains("女士"));
        if (linkman.getLinkmanSex() == NUMBER_0) {
            bookH5Vo.setLinkmanName(hasTitle ? name : name + "女士");
        } else {
            bookH5Vo.setLinkmanName(hasTitle ? name : name + "先生");
        }
        return ResultData.successData(bookH5Vo);
    }


    /**
     * 发送预定短信
     */
    @Override
    public ResultData sendSms(Long bookingId) {
        Booking booking = getById(bookingId);
        if (booking.getBookingStatus() !=1&&booking.getBookingStatus()!=2){
            return ResultData.noPermission("当前状态不能发送短信");
        }

//        //测试
//        if (booking.getBookingStatus()==1||booking.getBookingStatus()==7||booking.getBookingStatus()==null){
//            booking.setBookingStatus(7);
//        }else if (booking.getBookingStatus()==2||booking.getBookingStatus()==8){
//            booking.setBookingStatus(8);
//        }
//        booking.updateById();
//        log.info("发送短信：{}", booking);
//        BookNote bookNote = new BookNote();
//        bookNote.setBookingId(booking.getBookingId());
//        bookNote.setCompanyId(booking.getCompanyId());
//        bookNote.setCustomerId(booking.getCustomerId());
//        bookNote.setLinkmanId(booking.getLinkmanId());
//        bookNote.setBookingContent(getContent(booking));
//        bookNote.setBookingStatus(booking.getBookingStatus());
//        bookNote.insert();
//        return ResultData.successData(1);
//        //测试


        log.info("发送短信传入数据:={}", booking);
        Invite invite = inviteService.getOne(new LambdaQueryWrapper<Invite>().eq(Invite::getCustomerId, booking.getCustomerId()));
        log.info("邀请函：{}", invite);
        //返回0代表邀请函内容未填写，需要联系客服，1代表生成成功,2代表短信余额不足
        if (invite==null||invite.getBannerImg().isEmpty() || invite.getMessage().isEmpty() || invite.getAddress().isEmpty()) {
            return ResultData.failure("请完善邀请函内容");
        }
        YxSms yxSms = yxSmsService.getById(invite.getYxSmsId());
        Customer customer = customerService.getById(booking.getCustomerId());
        if (customer.getSmsTotal()==0){
            return ResultData.failure("短信余额不足");
        }
        String sign;
        if(customer.getIsPlatformSign()!=IS_PLATFORM_SIGN_FALSE){
            sign = SignEnum.getSign(customer.getIsPlatformSign());
        }else{
            sign = customer.getSign();
        }
        Company company = companyService.getById(booking.getCompanyId());
        Linkman linkman = linkmanService.getById(booking.getLinkmanId());
        String phone = linkman.getLinkmanPhone();
        Map<String, Object> requestMap = new HashMap<>();
        Map<String, Object> paramList = new HashMap<>();
        Map<String, Object> dyncParams = new HashMap<>();
        List<YxField> yxFieldList = yxFieldService.list(new LambdaQueryWrapper<YxField>().eq(YxField::getYxSmsId,invite.getYxSmsId()));
        for (YxField yxField : yxFieldList) {
            dyncParams.put(yxField.getYxFieldLabel(), getInfo(yxField.getYxFieldLabel(),yxField.getYxFieldValue(),company,linkman,booking,invite));
//            log.info("字段：{},字段值:{}", yxField.getYxFieldLabel(), getInfo(yxField.getYxFieldLabel(),yxField.getYxFieldValue(),company,linkman,booking,invite));
        }
        //客户标识
        paramList.put("custFlag", booking.getCustomerId().toString());
        paramList.put("dyncParams", dyncParams);
        //模板 ID
        requestMap.put("tplId", yxSms.getYxId().toString());
        //生成类型 1：标准生成短码 2：自定义生成短码
        requestMap.put("generationType", 1);
        //自定义短链域名
        requestMap.put("domain", "mhw9.cn");
        //参数对象集合
        requestMap.put("paramList", Collections.singletonList(paramList));
        //短信签名
        requestMap.put("smsSigns", Collections.singletonList(sign));
        //展示次数
        requestMap.put("showTimes", 1);
        //智能短信编码类型1:群发   2:个性化
        requestMap.put("aimCodeType", 2);
        String requestBody = JSON.toJSONString(requestMap);
        log.info("请求参数：{}", requestBody);
        String pwd = "1023468880179257344fOVikp";
        String account = "AP4025";
        //时间戳 获取月日时分秒的时间戳，定长 10 位，月、日、时、分、秒每段不足 2 位时左补 0
        String timestamp = new SimpleDateFormat("MMddHHmmss").format(new Date());
        pwd = account.toUpperCase() + "00000000" + pwd + timestamp;
        //MD5加密
        pwd = DigestUtils.md5Hex(pwd);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        log.info("account：{}", account);
        log.info("pwd：{}", pwd);
        log.info("timestamp：{}", timestamp);
        HttpPost httpPost = new HttpPost("https://surl-aim.monyun.cn:57126/ApiService/v1/SCodeManage/applyAimUrl");
        httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
        httpPost.setHeader("account", account);
        httpPost.setHeader("pwd", pwd);
        httpPost.setHeader("timestamp", timestamp);

        log.info("请求地址：{}", httpPost);
        httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            log.info("响应状态码：{}", response);
            HttpEntity entity = response.getEntity();
            String rawJson = EntityUtils.toString(entity, StandardCharsets.UTF_8);

            JSONObject resultJson = JSON.parseObject(rawJson);
            log.info("生成短链结果：{}", resultJson);
            log.info("生成短链结果：{}", resultJson.getString("subCode"));
            //将字符串转数字
            Integer subCode = Integer.parseInt(resultJson.getString("subCode"));
            if (subCode.equals(0)) {
                JSONObject data = resultJson.getJSONObject("data");
                log.info("短链结果data：{}", data);
                JSONArray paramArray = data.getJSONArray("paramList");
                log.info("短链结果paramArray：{}", paramArray);
                if (paramArray == null || paramArray.isEmpty()) {
                    log.error("短链结果异常：paramList为空");
                    return ResultData.failure("生成短链失败");
                }

                JSONObject firstParam = paramArray.getJSONObject(0);
                String aimUrl = firstParam.getString("aimUrl");
                log.info("短链结果aimUrl：{}", aimUrl);
                String content = "【" + sign + "】预订成功通知：" + linkman.getLinkmanName() + "您好，请查收您的预订信息和邀请函： " + aimUrl + " ，祝您万事如意，心想事成。";
                // 构建短信发送参数
                SendSmsModel sendSmsModel = new SendSmsModel(
                        phone,
                        content,
                        2
                );
                // 调用短信发送工具
                ResultData result = SmsPyUtil.sendCommonSms(sendSmsModel);
                log.info("短信发送结果:={}", JSON.toJSONString(result));
                //扣除短信余额
                reduceSmsUtil.reduceSms(customer.getCustomerId(),content,result,linkman,(long) NUMBER_0,TEMPLATE_CATEGORY_PRE_ORDER,null,NUMBER_0,null,1);
                log.info("短信发送结果：{}", booking.getBookingStatus());
                if (booking.getBookingStatus()==1||booking.getBookingStatus()==7||booking.getBookingStatus()==null){
                    booking.setBookingStatus(7);
                }else if (booking.getBookingStatus()==2||booking.getBookingStatus()==8){
                    booking.setBookingStatus(8);
                }
                booking.updateById();
                log.info("发送短信：{}", booking);
                BookNote bookNote = new BookNote();
                bookNote.setBookingId(booking.getBookingId());
                bookNote.setCompanyId(booking.getCompanyId());
                bookNote.setCustomerId(booking.getCustomerId());
                bookNote.setLinkmanId(booking.getLinkmanId());
                bookNote.setBookingContent(getContent(booking));
                bookNote.setBookingStatus(booking.getBookingStatus());
                bookNote.insert();
                log.info("发送短信：{}", bookNote);
                return ResultData.successData(NUMBER_1);
            }
            String failCodeEnum = MwFailCodeEnum.getMessage(subCode);
//            if (StringUtils.isEmpty(failCodeEnum)){
//                return ResultData.failure("生成短链失败");
//            }
            log.error("生成短链失败的错误信息：{}", failCodeEnum);
            return ResultData.failure("生成短链失败");
        } catch (Exception e) {
            return ResultData.failure("生成短链失败");
        }
    }
    private String getInfo(String yxFieldLabel,String yxFieldValue ,Company company,Linkman linkman,Booking booking,Invite invite){
        if (yxFieldValue.equals("companyName")){
            return company.getCompanyName();
        }else if (yxFieldValue.equals("linkmanName")){
            return linkman.getLinkmanName();
        }else if (yxFieldValue.equals("arriveDate")){
            return booking.getBookingDay() + " " + booking.getArrivalTime();
        }else if (yxFieldValue.equals("arrivalNum")){
            return booking.getArrivalNum()+ "人";
        }else if (yxFieldValue.equals("room")){
            return seatingService.getById(booking.getSeatingId()).getSeatingName() + " " + boothService.getById(booking.getBoothId()).getBoothName();
        } else if (yxFieldValue.equals("yxSmsId")) {
            return invite.getYxSmsId().toString();
        } else if (yxFieldValue.equals("customerId")) {
            return booking.getCustomerId().toString();
        }else if (yxFieldValue.equals("bookingId")){
            return booking.getBookingId().toString();
        }else if(yxFieldValue.equals("inviteTemplateId")){
            return invite.getInviteTemplateId().toString();
        }
        return "";
    }
    /**扣除短信余额*/
    private void deductSmsBalance(Integer smsNum,Long customerId) {
        Customer customer = customerService.getById(customerId);
        if (customer.getMessageNum() > smsNum-1 && customer.getSmsThaliNum() > smsNum-1) {
            // 获取会员有效期
            LocalDateTime memberExpire = customer.getMemberExpireTime();


            // 比较两个有效期（处理可能的null值）
            boolean useSmsPackage = customer.getSmsClearTime().isAfter(memberExpire);
            if (useSmsPackage) {
                customer.setMessageNum(customer.getMessageNum() - smsNum);
            } else {
                customer.setSmsThaliNum(customer.getSmsThaliNum() - smsNum);
            }
        } else if (customer.getMessageNum() > smsNum-1) {
            customer.setMessageNum(customer.getMessageNum() - smsNum);
        } else if (customer.getSmsThaliNum() > smsNum-1) {
            customer.setSmsThaliNum(customer.getSmsThaliNum() - smsNum);
        }
        customer.setSmsTotal(customer.getSmsTotal() - smsNum);
        customer.setCurrentSendTimes(customer.getCurrentSendTimes() + 1);
        customer.setPlatformSendTimes(customer.getPlatformSendTimes() + 1);
        customer.setSendTimes(customer.getSendTimes() + 1);
        LocalDateTime now = LocalDateTime.now();
        customer.setLastSendTime(now);
        customer.updateById();
        String cacheKey = APP + "_" + customer.getCustomerId();
        // 使用标准JSON序列化
        redisClient.save(cacheKey, JSON.toJSONString(customer));
    }
}
